package edu.kit.ksri.db.mturk.connectionhandlers;

import org.apache.log4j.Logger;

import com.amazonaws.mturk.requester.Assignment;
import com.amazonaws.mturk.requester.HIT;

import edu.kit.ksri.db.mturk.utils.messaging.Result;
import edu.kit.ksri.db.mturk.utils.messaging.ResultOutputCollector;
import edu.kit.ksri.db.mturk.var.ConnectionMode;
import edu.kit.ksri.db.mturk.var.StaticInformation;

/**
 * Copyright (c) 2010-2011 Karlsruhe Institute of Technology (KIT), Germany
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 * 
 * --------------------------------------------------------------------------
 * 
 * Software: CSP/WMV tool for dynamic quality management of microtasks
 * http://www.ksri.kit.edu/Upload/Users/PeopleClouds/HCOMP2011_An_extendable_toolkit_for_managing_quality_of_human-based_eServices.pdf
 * 
 * Organization: Karlsruhe Institute of Technology (KIT), Germany
 * http://www.kit.edu
 * 
 * Project: PeopleClouds project of the Karlsruhe Service Research Institute(KSRI)
 * http://www.ksri.kit.edu/Default.aspx?PageId=818
 * 
 * Contributing authors: David Bermbach, Sandra Rath, Pascal Wichmann, Robert Kern
 */
public abstract class AbstractHITManager {

	/** HITManager Singleton */
	protected static AbstractHITManager instance;
	
	private static final Logger basiclog = Logger
	.getLogger("basic." + AbstractHITManager.class);

	/**
	 * 
	 * @return the {@link HITManager} singleton
	 */
	public static AbstractHITManager getInstance() {
		if (instance == null) {
			if (StaticInformation.scenario.getConnectionMode() == ConnectionMode.PERFSIM) {
				instance = new PerfSimHITManager();
			} 
			else if (StaticInformation.scenario.getConnectionMode() == ConnectionMode.CORRSIM) {
				instance = new CorrSimHITManager();
			}
			else if (StaticInformation.scenario.getConnectionMode() == ConnectionMode.SIM) {
				instance = new SimHITManager();
			}
			else{
				//for live mode and for corrsiminput mode
				instance = new HITManager();
			}
		}
		return instance;
	}

	/**
	 * Check to see if your account has sufficient funds
	 * 
	 * @return true if there are sufficient funds. False if not.
	 */
	public abstract boolean hasEnoughFund();

	/**
	 * requests another assignment for the specified hit
	 * 
	 * @param hitId
	 *            the hit which shall be extended
	 * @return whether the operation was successful or not
	 */
	protected abstract boolean extendHitInternal(String hitId);

	/**
	 * requests another assignment for the specified hit
	 * 
	 * @param hitId
	 *            the hit which shall be extended
	 * @return whether the operation was successful or not
	 */
	public boolean extendHit(String hitId) {
		return this.extendHitInternal(hitId);
	}
	
	

	/**
	 * get Account Balance
	 * 
	 * @return Account Balance value
	 */
	public abstract double accountBalance();

	/**
	 * deletes the specified hit
	 * 
	 * @param hitid
	 * @return true if no error occurred, false otherwise
	 */
	public abstract boolean deleteHit(String hitid);

	/**
	 * approves an assignment
	 * 
	 * @param assignmentid
	 *            the assignment which shall be approved
	 * @param feedback
	 *            an optional comment
	 * @return true if no error occurred, false otherwise
	 */
	public abstract boolean approveAssignment(String assignmentid,
			String feedback);

	/**
	 * rejects an assignment
	 * 
	 * @param assignmentid
	 *            the assignment which shall be rejected
	 * @param feedback
	 *            an optional comment
	 * @return true if no error occurred, false otherwise
	 */
	public abstract boolean rejectAssignment(String assignmentid,
			String feedback);

	/**
	 * 
	 * @param hittypeid
	 * @return the number of completed HITs or -1 if an error occurred
	 */
	public abstract int getNumberOfCompletedHITs(String hittypeid);

	/**
	 * returns all known HIT IDs or an empty array if an error occurred.
	 * 
	 * @return
	 */
	public abstract String[] getAllHITIDs();
	
	/**
	 * returns all known HITs or null if an error occurred.
	 * 
	 * @return
	 */
	public abstract HIT[] getAllHITs();
	
	/**
	 * returns all known HITs for HIT Type id or null if an error occurred or non existing.
	 * 
	 * @return
	 */
	public abstract HIT[] getAllHITsForHITType();

	/**
	 * returns all known HIT IDs for which already exist all assignments or an
	 * empty array if an error occurred.
	 * 
	 * @return
	 */
	public abstract String[] getAllReviewableHITIDs();

	/**
	 * retrieves all assignments for the specified hit id or an empty array if
	 * an error occurred.
	 * 
	 * should be combined with getAllHITIDs()
	 * 
	 * @param hitid
	 * @return
	 */
	public abstract Assignment[] getAssignmentsForHITID(String hitid);

	/**
	 * 
	 * @param hittypeid
	 * @return the number of HITs or -1 if an error occurred
	 */
	public abstract int getNumberOfHITs(String hittypeid);

	/**
	 * Creates a number of hits based on the parameters
	 * 
	 * @param inputFile
	 * @param questionFile
	 * @param propertiesFile
	 * @return the created {@link HIT} object or null if an error occurred.
	 */
	protected abstract HIT[] createHITsInternal(String inputFile,
			String questionFile, String propertiesFile);

	/**
	 * Creates a number of hits based on the parameters
	 * 
	 * @param inputFile
	 * @param questionFile
	 * @param propertiesFile
	 * @return the created {@link HIT} object or null if an error occurred.
	 */
	public HIT[] createHITs(String inputFile, String questionFile,
			String propertiesFile) {
		HIT[] h = this.createHITsInternal(inputFile, questionFile,
				propertiesFile);
		if(StaticInformation.scenario.getConnectionMode()== ConnectionMode.CORRSIMINPUT){
			ResultOutputCollector.getInstance().addRequestedAssignments(h.length*StaticInformation.scenario.getSimulationHitCount());
		}
		else{
			ResultOutputCollector.getInstance().addRequestedAssignments(h.length);
		}
		return h;
	}
	
	/**
	 * Checks if there are HITs uploaded and if yes, then no new HITs will be created. 
	 * Instead the previous session will be continued
	 * 
	 * @return the already existing HITs
	 */
	public HIT[] continuePreviousRun(){

		HIT[] h = this.getAllHITsForHITType();
		
		if(h != null){
			//HITs for this HIT type are already there, so continue with previous run
			if(StaticInformation.scenario.getConnectionMode() == ConnectionMode.CORRSIMINPUT){
				ResultOutputCollector.getInstance().addRequestedAssignments(h.length*StaticInformation.scenario.getSimulationHitCount());
			}
			else{
				ResultOutputCollector.getInstance().addRequestedAssignments(h.length);
			}
			
			basiclog.info("Important: Previous run will be continued since there are already some HITs for this HIT type on MTurk.");
			return h;
		}
		else{
			//No hits for this HIT type existing
			return null;
		}
		
	}

}